<?php
/**
 * Debug Class
 *
 * @author Matt Pike
 * @package Mhtml
 */
class Debug extends MhtmlModel{

	private static $_instance = null;
	private $usedOnce	= false;
	public $_tbl		= "mhtml_log";
	public $_tbl_key	= "id";

	public $id	= null;
	public $date	= null;
	public $ctrl	= null;
	public $action	= null;
	public $log		= null;
	public $userId 	= null;
	public $reqType = null;
	public $get		= null;
	public $post	= null;
	public $files	= null;
	public $ref		= null;
	public $exceptionType = null;
	public $exceptionCode = null;
	public $exceptionMsg = null;

	/**
	 * Note: This class is a singleton, use getInstance() rather than instantiating directly
	 */
	public function __construct(){
		$my = MhtmlCore::getUser();
		$this->_db 	= MhtmlCore::getDatabase();
		//$this->load(null,false);
		$this->date		= date("Y-m-d H:i:s");
		$this->userId 	= $my->id;
		$this->reqType	= MhtmlRequest::getParam("respType");
		$this->ctrl 	= MhtmlRequest::getParam("ctrl");
		$this->action 	= MhtmlRequest::getParam("action");
		$this->get		= $this->_db->getEscaped(json_encode($_GET));
		$this->post		= $this->_db->getEscaped(json_encode($_POST));
		$this->files	= $this->_db->getEscaped(json_encode($_FILES));
		global $mosConfig_live_site;
		$this->ref		= $this->_db->getEscaped(str_replace($mosConfig_live_site,"",@$_SERVER["HTTP_REFERER"]));
	}

	public function __destruct(){
		try{
			$this->store();
		}catch(Exception $e){
			mosMail("joomla@notify.strategiesuk.net","Mybookkeepingonline",Config::email_Webmasters,"Error saving log",print_r($e,true));
		}
	}
	
	/**
	 * Singleton function
	 *
	 * @return MhtmlDebug
	 */
	public static function getInstance(){
		if(is_null(self::$_instance)){
			self::$_instance = new MhtmlDebug();
			return self::$_instance;
		}else{
			return self::$_instance;
		}
	}

	/**
	 * Trace a program event that is worth noting
	 *
	 * @param string $info
	 * @param int $level
	 */
	public function trace($info,$level=1,$vardump=null){
		if($info){
			$debug = self::getInstance();
			if(!$debug->log) $debug->log .= "++ Starting trace:\r\n---------------------\r\n";
			$levelStr = "";
			for($n=0;$n<$level;$n++){
				$levelStr .= "- ";
			}
			if(is_array($vardump)){
				$debug->log .= $levelStr.$info.": "."\r\n";
				$levelStr .= "- ";
				foreach($vardump as $k => $v){
					//error_log("- ".$line);
					if($v===true) $v = "True";
					if($v===false) $v = "False";
					if(strlen($v)) $debug->log .= $levelStr.($v ? htmlentities("[".$k."] = ".$v) : "")."\r\n";
				}
			}else{
				$debug->log .= $levelStr.$info.($vardump ? ": ".htmlentities($vardump) : "")."\r\n";
			}
			
		}
	}

	/**
	 * Pass in a question and a function result and get a true/false debug trace
	 *
	 * @param string $question
	 * @param boolean $answer
	 * @param int $level
	 */
	public function traceQuestion($question,$answer,$level){
		$answer = $answer ? "True" : "False";
		self::trace($question.": ".$answer,$level);
	}

	/**
	 * Add a line to divide trace content
	 *
	 * @param string $anchor - optional anchor to link to part of page
	 */
	public function addTraceDivider($anchor=null){
		$debug = self::getInstance();
		$debug->log .= "---------------------".($anchor ? " <a href='".@$_SERVER["REDIRECT_URL"]."#".ltrim($anchor,"#")."'>#$anchor</a>" : "")."\r\n";
	}

	public function outputTraceWindow(){
		$debug = self::getInstance();
		echo "<pre id='traceLog' style='z-index:9999; position:fixed; line-height:2em; right:0; top:0; width:350px; height:20px; overflow:scroll; background:#333; color:#aaa; padding-top:35px; font-family:\"Lucida Console\"; font-size:10px'>";
		echo "<span style='position:fixed;border:1px dotted #fff; right:25px; top:10px; padding:0 3px; background:#222'><b>Debug Log:</b>";
		echo "[<a onclick='this.getParent(\"pre\").getElement(\"#traceLogText\").set(\"html\",\"\")' style='color:#888' title='Clear Log Contents'>Clr.</a>]";
		//echo "[<a onclick='this.getParent(\"pre\").set(\"styles\",{\"width\":\"20%\",\"height\":\"100%\",\"left\":\"0\",\"top\":\"0\",\"right\":\"auto\",\"bottom\":\"auto\"})' style='color:#888' title='Position Left'>Lft.</a>]";
		echo "[<a onclick='this.getParent(\"pre\").set(\"styles\",{\"width\":\"20%\",\"height\":\"100%\",\"right\":\"0\",\"top\":\"0\",\"left\":\"auto\",\"bottom\":\"auto\"})' style='color:#888' title='Position Side'>Side</a>]";
		echo "[<a onclick='this.getParent(\"pre\").set(\"styles\",{\"width\":\"100%\",\"height\":\"20%\",\"left\":\"0\",\"top\":\"auto\",\"right\":\"auto\",\"bottom\":\"0\"})' style='color:#888' title='Position Bottom'>Btm.</a>]";
		echo "[<a onclick='this.getParent(\"pre\").set(\"styles\",{\"width\":\"350px\",\"height\":\"20px\"})' style='color:#888' title='Minimize Debug Window'>Min.</a>]";
		echo "[<a onclick='this.getParent(\"pre\").set(\"styles\",{\"width\":\"100%\",\"height\":\"100%\",\"left\":\"0\",\"top\":\"0\",\"right\":\"auto\",\"bottom\":\"auto\"})' style='color:#888' title='Maximize Debug Window'>Max.</a>]";
		echo "[<a onclick='this.getParent(\"pre\").addClass(\"hide\")' style='color:#888' title='Close Debug Window'>Cls.</a>]";
		echo "</span>";
		echo "<span id='traceLogText'>$debug->log</span>";
		echo "</pre>";
	}

	/**
	 * Log an internal error/warning/event
	 *
	 * @param string $description
	 * @param mixed $vardump
	 * @param string $type
	 */
	public function log($description,$vardump=null,$type="Info",$throwException=false){
		$debug = self::getInstance();
		if(is_array($vardump) || is_object($vardump)){
			$vardump = print_r($vardump,true);
			$vardump = explode("\n",$vardump,500);
		}
		if(is_array($vardump)){
			if(!$throwException) error_log("[$type] $description: ");
			$debug->trace("[$type] $description: ");
			foreach($vardump as $line){
				error_log("- ".$line);
				$debug->trace($line,1);
			}
		}else{
			if(!$throwException) error_log("[$type] $description: $vardump");
			$debug->trace("[$type] $description: $vardump");
		}
		if($throwException){
			$debug->trace("------------------- EXECUTION ABORTED");
			$debug->dumpExisting(); // dump contents of log before triggering error
			throw new Exception("[$type] $description".($vardump ? ": ".print_r($vardump,true) : ""));
		}
	}

	/**
	 * Trigger and log a site error
	 *
	 * @param Exception $e
	 */
	public function logException(Exception $e,$type="GeneralException"){
		$debug = self::getInstance();
		$debug->exceptionType = $type;
		$debug->exceptionCode = $e->getCode();
		$debug->exceptionMsg = $e->getMessage();
		$exceptionInfo = array("Location"=>$e->getFile()." on Line ".$e->getLine(), "Trace"=>"\n".$e->getTraceAsString());
		if($e->getCode()) 	$exceptionInfo["Code"] = $e->getCode();
		if($e instanceof GeneralException)$exceptionInfo["Var Dump"] = $e->getVarDump();
		self::log($e->getMessage(),$exceptionInfo,"Error",false);
	}

	/**
	 * Useful function if you wanna output something only once i.e. one iteration of a loop
	 */
	public function once($string){
		$debug = self::getInstance();
		if($debug->usedOnce){
			return null;
		}else{
			$debug->usedOnce = true;
			return $string;
		}
	}
	
	public function getLogId(){
		$debug = self::getInstance();
		if($debug->id){
			return $debug->id;
		}else{
			$debug->store();
			return $debug->id;
		}
	}
}
